
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <string.h>
#include <jni.h>
#include "HTS_engine.h"

#include <android/log.h>

#define LOG_TAG   "libAMIT_HTS_ENGINE"
#define LOGI(ARG)  __android_log_write(ANDROID_LOG_INFO,LOG_TAG,ARG)
#define LOGE(ARG)  __android_log_write(ANDROID_LOG_ERROR,LOG_TAG,ARG)








#define INPUT_BUFF_SIZE 2048

void Usage_new(void)
{
   fprintf(stderr, "\n");
   fprintf(stderr, "hts_engine - An HMM-based speech synthesis engine\n");
   fprintf(stderr, "Modified by Akshar Speech Technologies which uses mixed excitation\n");
   fprintf(stderr, "\n");
   fprintf(stderr, "  usage:\n");
   fprintf(stderr, "       engine [ rms Dir ] [ infile ] [ wavfile ] \n");
   fprintf(stderr, "***********************************************************\n");
   exit(0);
           
    
}
/* Usage: output usage */

/* Error: output error message */
void Error(const int error, char *message, ...)
{
   va_list arg;

   fflush(stdout);
   fflush(stderr);

   if (error > 0)
      fprintf(stderr, "\nError: ");
   else
      fprintf(stderr, "\nWarning: ");

   va_start(arg, message);
   vfprintf(stderr, message, arg);
   va_end(arg);

   fflush(stderr);

   if (error > 0)
      exit(error);
}

/* Getfp: wrapper for fopen */
FILE *Getfp(const char *name, const char *opt)
{
   FILE *fp = fopen(name, opt);

   if (fp == NULL)
      Error(2, "Getfp: Cannot open %s.\n", name);

   return (fp);
}

/* GetNumInterp: get number of speakers for interpolation from argv */
int GetNumInterp(int argc, char **argv_search)
{
   int num_interp = 1;
   while (--argc) {
      if (**++argv_search == '-') {
         if (*(*argv_search + 1) == 'i') {
            num_interp = atoi(*++argv_search);
            if (num_interp < 1) {
               num_interp = 1;
            }
            --argc;
         }
      }
   }
   return (num_interp);
}

char *addTwoStrings(const char *str1, char *str2);



int AMIT_TTS_ENGINE(char *dir, char *fname, char *wavfile)
{


   int i;
   double f;
   char *labfn = NULL;
#ifndef HTS_EMBEDDED
   FILE *lf0fp = NULL, *mcpfp = NULL;
#endif                          /* !HTS_EMBEDDED */
   FILE *durfp = NULL, *wavfp = NULL, *rawfp = NULL, *tracefp = NULL, *txtfp = NULL;

   char txt[INPUT_BUFF_SIZE];

   /* number of speakers for interpolation */
   int num_interp = 0;
   double *rate_interp = NULL;

   /* file names of models */
   char **fn_ms_lf0;
   char **fn_ms_mcp;
   char **fn_ms_dur;
   char **fn_ms_str;
   /* number of each models for interpolation */
   int num_ms_lf0 = 0, num_ms_mcp = 0, num_ms_dur = 0, num_ms_str = 0;

   /* file names of trees */
   char **fn_ts_lf0;
   char **fn_ts_mcp;
   char **fn_ts_dur;
   char **fn_ts_str;
   /* number of each trees for interpolation */
   int num_ts_lf0 = 0, num_ts_mcp = 0, num_ts_dur = 0, num_ts_str = 0;

   /* file names of windows */
   char **fn_ws_lf0 = NULL;
   char **fn_ws_mcp;
   char **fn_ws_str;
   int num_ws_lf0 = 0, num_ws_mcp = 0, num_ws_str = 0;

   /* file names of global variance */
   char **fn_ms_gvl = NULL;
   char **fn_ms_gvm = NULL;
   char **fn_ms_gvs = NULL;
   int num_ms_gvl = 0, num_ms_gvm = 0, num_ms_gvs = 0;

   /* file names of global variance trees */
   char **fn_ts_gvl = NULL;
   char **fn_ts_gvm = NULL;
   char **fn_ts_gvs = NULL;
   int num_ts_gvl = 0, num_ts_gvm = 0, num_ts_gvs = 0;

   /* file name of global variance switch */
   char *fn_gv_switch = NULL;

   /* global parameter */
   int sampling_rate = 16000;
   int fperiod = 80;
   double alpha = 0.42;
   double stage = 0.0;          /* gamma = -1.0/stage */
   double beta = 0.0;
   int audio_buff_size = 1600;
   double uv_threshold = 0.5;
   double gv_weight_lf0 = 0.7;
   double gv_weight_mcp = 1.0;
   double gv_weight_str = 1.0;

   double half_tone = 0.0;
   HTS_Boolean phoneme_alignment = FALSE;
   double speech_speed = 1.0;
   HTS_Boolean use_log_gain = FALSE;

   /* label list*/
   char **label_data = NULL;
   int label_size;

   /* engine */ // 
   HTS_Engine engine;

   /* parse command line */
  /* if (argc < 4)
      Usage_new();*/
   
   
   /* Code Inserted By Amit 
   dir=argv[1];
   fname=argv[2];
   wavfile=argv[3];
   
    Code Inserted By Amit */
   
// INIT
   /* initialize (stream[0] = spectrum , stream[1] = lf0) */
   HTS_Engine_initialize(&engine, 3);


   /* prepare for interpolation */
   num_interp =  1; /*GetNumInterp(argc, argv);*/
   rate_interp = (double *) calloc(num_interp, sizeof(double));
   for (i = 0; i < num_interp; i++)
      rate_interp[i] = 1.0;

   fn_ms_lf0 = (char **) calloc(num_interp, sizeof(char *));
   fn_ms_mcp = (char **) calloc(num_interp, sizeof(char *));
   fn_ms_dur = (char **) calloc(num_interp, sizeof(char *));
   fn_ms_str = (char **) calloc(num_interp, sizeof(char *));
   
   fn_ts_lf0 = (char **) calloc(num_interp, sizeof(char *));
   fn_ts_mcp = (char **) calloc(num_interp, sizeof(char *));
   fn_ts_dur = (char **) calloc(num_interp, sizeof(char *));
   fn_ts_str = (char **) calloc(num_interp, sizeof(char *));
   
   fn_ms_gvl = (char **) calloc(num_interp, sizeof(char *));
   fn_ms_gvm = (char **) calloc(num_interp, sizeof(char *));
   fn_ms_gvs = (char **) calloc(num_interp, sizeof(char *));
   
   fn_ts_gvl = (char **) calloc(num_interp, sizeof(char *));
   fn_ts_gvm = (char **) calloc(num_interp, sizeof(char *));
   fn_ts_gvs = (char **) calloc(num_interp, sizeof(char *));

   /* delta window handler for log f0 */
  fn_ws_lf0 = (char **) calloc(3, sizeof(char *));
  /* delta window handler for mel-cepstrum */
  fn_ws_mcp = (char **) calloc(3, sizeof(char *));
  /* delta window handler for strengths */
  fn_ws_str = (char **) calloc(3, sizeof(char *));
 

 
   fn_ts_dur[num_ts_dur++] = addTwoStrings(dir, "/t.1");
   fn_ts_lf0[num_ts_lf0++] = addTwoStrings(dir, "/p.1");
   fn_ts_mcp[num_ts_mcp++] = addTwoStrings(dir, "/s.1");
   fn_ts_str[num_ts_str++] = addTwoStrings(dir, "/b.1");

   fn_ms_dur[num_ms_dur++] = addTwoStrings(dir, "/k.1");
   fn_ms_lf0[num_ms_lf0++] = addTwoStrings(dir, "/v.1");
   fn_ms_mcp[num_ms_mcp++] = addTwoStrings(dir, "/sy.1");
   fn_ms_str[num_ms_str++] = addTwoStrings(dir, "/r.1");

   fn_ws_lf0[num_ws_lf0++] = addTwoStrings(dir, "/l.w1");
   fn_ws_lf0[num_ws_lf0++] = addTwoStrings(dir, "/l.w2");
   fn_ws_lf0[num_ws_lf0++] = addTwoStrings(dir, "/l.w3");
   fn_ws_mcp[num_ws_mcp++] = addTwoStrings(dir, "/m.w1");
   fn_ws_mcp[num_ws_mcp++] = addTwoStrings(dir, "/m.w2");
   fn_ws_mcp[num_ws_mcp++] = addTwoStrings(dir, "/m.w3");
   fn_ws_str[num_ws_str++] = addTwoStrings(dir, "/s.w1");
   fn_ws_str[num_ws_str++] = addTwoStrings(dir, "/s.w2");
   fn_ws_str[num_ws_str++] = addTwoStrings(dir, "/s.w3");
   
   /* number of models,trees check */
   if (num_interp != num_ts_lf0 || num_interp != num_ts_mcp ||
       num_interp != num_ts_dur || num_interp != num_ms_lf0 ||
       num_interp != num_ms_mcp || num_interp != num_ms_dur) {
      Error(1,
            "hts_engine: specify %d models(trees) for each parameter.\n",
            num_interp);
   }
     wavfp = Getfp(wavfile, "wb");

/* */

   /* load duration model */
   HTS_Engine_load_duration_from_fn(&engine, fn_ms_dur, fn_ts_dur, num_interp);
   /* load stream[0] (spectrum model) */
   HTS_Engine_load_parameter_from_fn(&engine, fn_ms_mcp, fn_ts_mcp, fn_ws_mcp,
                                     0, FALSE, num_ws_mcp, num_interp);
   /* load stream[1] (lf0 model) */
   HTS_Engine_load_parameter_from_fn(&engine, fn_ms_lf0, fn_ts_lf0, fn_ws_lf0,
                                     1, TRUE, num_ws_lf0, num_interp);
   HTS_Engine_load_parameter_from_fn(&engine, fn_ms_str, fn_ts_str, fn_ws_str,
                                     2, FALSE, num_ws_str, num_interp);

   /* load gv[0] (GV for spectrum) */
   if (num_interp == num_ms_gvm) {
      if (num_ms_gvm == num_ts_gvm)
         HTS_Engine_load_gv_from_fn(&engine, fn_ms_gvm, fn_ts_gvm, 0,
                                    num_interp);
      else
         HTS_Engine_load_gv_from_fn(&engine, fn_ms_gvm, NULL, 0, num_interp);
   }
   /* load gv[1] (GV for lf0) */
   if (num_interp == num_ms_gvl) {
      if (num_ms_gvl == num_ts_gvl)
         HTS_Engine_load_gv_from_fn(&engine, fn_ms_gvl, fn_ts_gvl, 1,
                                    num_interp);
      else
         HTS_Engine_load_gv_from_fn(&engine, fn_ms_gvl, NULL, 1, num_interp);
   }
   /* load gv[2] (GV for strengths) */
   if (num_interp == num_ms_gvs) {
      if (num_ms_gvs == num_ts_gvs)
         HTS_Engine_load_gv_from_fn(&engine, fn_ms_gvs, fn_ts_gvs, 2,
                                    num_interp);
      else
         HTS_Engine_load_gv_from_fn(&engine, fn_ms_gvs, NULL, 2, num_interp);
   }
   /* load GV switch */
   if (fn_gv_switch != NULL)
      HTS_Engine_load_gv_switch_from_fn(&engine, fn_gv_switch);

   /* set parameter */
   HTS_Engine_set_sampling_rate(&engine, sampling_rate);
   HTS_Engine_set_fperiod(&engine, fperiod);
   HTS_Engine_set_alpha(&engine, alpha);
   HTS_Engine_set_gamma(&engine, stage);
   HTS_Engine_set_log_gain(&engine, use_log_gain);
   HTS_Engine_set_beta(&engine, beta);
   HTS_Engine_set_audio_buff_size(&engine, audio_buff_size);
   HTS_Engine_set_msd_threshold(&engine, 1, uv_threshold);      /* set voiced/unvoiced threshold for stream[1] */
   HTS_Engine_set_gv_weight(&engine, 0, gv_weight_mcp);
   HTS_Engine_set_gv_weight(&engine, 1, gv_weight_lf0);
   HTS_Engine_set_gv_weight(&engine, 2, gv_weight_str);
   for (i = 0; i < num_interp; i++) {
      HTS_Engine_set_duration_interpolation_weight(&engine, i, rate_interp[i]);
      HTS_Engine_set_parameter_interpolation_weight(&engine, 0, i,
                                                    rate_interp[i]);
      HTS_Engine_set_parameter_interpolation_weight(&engine, 1, i,
                                                    rate_interp[i]);
	  HTS_Engine_set_parameter_interpolation_weight(&engine, 2, i,
                                                    rate_interp[i]);
   }
   if (num_interp == num_ms_gvm)
      for (i = 0; i < num_interp; i++)
         HTS_Engine_set_gv_interpolation_weight(&engine, 0, i, rate_interp[i]);
   if (num_interp == num_ms_gvl)
      for (i = 0; i < num_interp; i++)
         HTS_Engine_set_gv_interpolation_weight(&engine, 1, i, rate_interp[i]);
   if (num_interp == num_ms_gvs)
      for (i = 0; i < num_interp; i++)
         HTS_Engine_set_gv_interpolation_weight(&engine, 2, i, rate_interp[i]);

// end INIT


// SYTM
   if( (txtfp = Getfp(fname, "r")) == NULL) return 0;
   if (fgets(txt, INPUT_BUFF_SIZE, txtfp) != NULL && strlen(txt) > 0)
   {
	   txt[strlen(txt)-1] = '\0';
	   label_data = Flite_HTS_Engine_L2S(txt, &label_size);
   }

   /* synthesis */
   HTS_Engine_load_label_from_string_list(&engine, label_data, label_size);       /* load label file */

   if (phoneme_alignment)       /* modify label */
      HTS_Label_set_frame_specified_flag(&engine.label, TRUE);
   if (speech_speed != 1.0)     /* modify label */
      HTS_Label_set_speech_speed(&engine.label, speech_speed);
   HTS_Engine_create_sstream(&engine);  /* parse label and determine state duration */
   if (half_tone != 0.0) {      /* modify f0 */
      for (i = 0; i < HTS_SStreamSet_get_total_state(&engine.sss); i++) {
         f = HTS_SStreamSet_get_mean(&engine.sss, 1, i, 0);
         f += half_tone * log(2.0) / 12;
         if (f < log(10.0))
            f = log(10.0);
         HTS_SStreamSet_set_mean(&engine.sss, 1, i, 0, f);
      }
   }
   HTS_Engine_create_pstream(&engine);  /* generate speech parameter vector sequence */
   HTS_Engine_create_gstream(&engine);  /* synthesize speech */
// end syth

// OUTPUT
   /* output */
   if (tracefp != NULL)
      HTS_Engine_save_information(&engine, tracefp);
   if (durfp != NULL)
      HTS_Engine_save_label(&engine, durfp);
   if (rawfp)
      HTS_Engine_save_generated_speech(&engine, rawfp);
   if (wavfp)
      HTS_Engine_save_riff(&engine, wavfp);
#ifndef HTS_EMBEDDED
   if (mcpfp)
      HTS_Engine_save_generated_parameter(&engine, mcpfp, 0);
   if (lf0fp)
      HTS_Engine_save_generated_parameter(&engine, lf0fp, 1);
#endif                          /* !HTS_EMBEDDED */

// output
// Destory
   /* free */
   HTS_Engine_refresh(&engine);

   /* free memory */
   HTS_Engine_clear(&engine);
   free(rate_interp);
   free(fn_ws_mcp);
   free(fn_ws_lf0);
   free(fn_ms_mcp);
   free(fn_ms_lf0);
   free(fn_ms_dur);
   free(fn_ts_mcp);
   free(fn_ts_lf0);
   free(fn_ts_dur);
   free(fn_ms_gvm);
   free(fn_ms_gvl);
   free(fn_ts_gvm);
   free(fn_ts_gvl);

   /* close files */
#ifndef HTS_EMBEDDED
   if (mcpfp != NULL)
      fclose(mcpfp);
   if (lf0fp != NULL)
      fclose(lf0fp);
#endif                          /* !HTS_EMBEDDED */
   if (wavfp != NULL)
      fclose(wavfp);
   if (rawfp != NULL)
      fclose(rawfp);
   if (durfp != NULL)
      fclose(durfp);
   if (tracefp != NULL)
      fclose(tracefp);

   return 0;
}
char* addTwoStrings(const char* str1, char* str2) {
    int m,n, t;
    int i, j;
    char *newString;
    m=strlen(str1);
    n=strlen(str2);
    t = m+n;

    newString = (char *) malloc(t); //*sizeof(char));

    for (i=0; i<m; i++)
    {
        newString[i] = str1[i];
    }
    for (j=0; j<n; j++)
    {
        newString[i+j] = str2[j];
    }
    newString[t] = '\0';
    return newString;

}

/*NDK PART */

JNIEXPORT jstring JNICALL 
Java_com_test_TestMe_stringFromJNI(JNIEnv* env, jobject this)
{
	return(*env)->NewStringUTF(env,"Msg: Who Told You NDK is tough!");
}

JNIEXPORT jstring JNICALL 
Java_com_test_TestMe_ENGINE(JNIEnv* env,jobject this, jstring dir, jstring textfile, jstring wavfile)
{

	int x=0;
	const char *j_dir, *j_text, *j_wav;
     j_dir = (*env)->GetStringUTFChars(env, dir, 0);

     j_text = (*env)->GetStringUTFChars(env, textfile, 0);

     j_wav = (*env)->GetStringUTFChars(env, wavfile, 0);

     x=AMIT_TTS_ENGINE("/sdcard/rms","/sdcard/amit.txt","/sdcard/amit.wav");





      (*env)->ReleaseStringUTFChars(env, wavfile, j_wav);
      (*env)->ReleaseStringUTFChars(env, dir, j_dir);
      (*env)->ReleaseStringUTFChars(env, textfile, j_text);

	//strcat(msg,j_dir);
	
	
	//LOGI(msg);
	


	if(x==0)
		return (*env)->NewStringUTF(env,"The Wav file is created. Read to be played");
	else 
		return (*env)->NewStringUTF(env,"ERROR");


}
